﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Microsoft.Kinect;
using VideoMagic.EffectsLibrary;
using VideoMagic.Extensions;

namespace VideoMagic
{
    public class KinectVideoMerge
    {
        int _Width = 640;
        int _Height = 480;
        int _PixelCount;
        const int _BytesPerDepthPixel = 2;
        const int _BytesPerColorPixel = 4;
        static Int32Rect _ViewPort;

        public Dictionary<LayerName, VideoMagicImage> Layers = new Dictionary<LayerName, VideoMagicImage>();
        Dictionary<LayerName, bool> LayerVisibility = new Dictionary<LayerName, bool>();

        //VideoMagicImage _Output;

        public enum LayerName
        {
            Background = 0,
            Main = 1,
            Foreground = 2
        }

        private void InitWidthHeight(int width, int height)
        {
            _Width = width;
            _Height = height;

            _PixelCount = _Width * _Height;
            _ViewPort = new Int32Rect(0, 0, _Width, _Height);

            VideoMagicImage _Output = new VideoMagicImage(_Width, _Height);
        }

        public KinectVideoMerge(int width, int height)
        {
            InitWidthHeight(width, height);

            Layers.Add(LayerName.Background, new VideoMagicImage(_Width, _Height));
            Layers.Add(LayerName.Main, new VideoMagicImage(_Width, _Height));
            Layers.Add(LayerName.Foreground, new VideoMagicImage(_Width, _Height));

            LayerVisibility.Add(LayerName.Background, true);
            LayerVisibility.Add(LayerName.Main, true);
            LayerVisibility.Add(LayerName.Foreground, true);

            //byte[] red = new byte[] { 0, 0, 255, 255 };
            //byte[] green = new byte[] { 0, 255, 0, 255 };

            //short[] depthLayer = Layers[LayerName.Background].DepthData;
            //float depthLayerLength = depthLayer.Length;
            //float maxValue = ushort.MaxValue;
            //short[] lastFive = new short[5];

            //for (float i = 0; i < depthLayerLength; i++)
            //{
            //    ushort value = Convert.ToUInt16(maxValue * i / depthLayerLength);
            //    short shortValue;

            //    if (value > short.MaxValue)
            //    {
            //        shortValue = (short)(-1 * (value - 32768));
            //    }
            //    else
            //    {
            //        shortValue = (short)value;
            //    }

            //    depthLayer[(int)i] = shortValue;
            //    lastFive[(int)i % 5] = shortValue;
            //}

            DepthImagePixel depthPixel = new DepthImagePixel { Depth = 0, PlayerIndex = 0 };

            Layers[LayerName.Background].DepthData.Fill(short.MaxValue);
            //Layers[LayerName.Background].DepthData.Fill(depthPixel);
            Layers[LayerName.Background].ColorData.Fill((byte)255);
            Layers[LayerName.Foreground].DepthData.Fill(short.MaxValue);
            //Layers[LayerName.Foreground].DepthData.Fill(depthPixel);
            Layers[LayerName.Foreground].ColorData.Fill(_bluePixel);
        }

        //public void UpdateMainLayerColor(ColorImageFrame imageFrame)
        //{
        //    if (imageFrame == null)
        //    {
        //        return;
        //    }

        //    imageFrame.CopyPixelDataTo(Layers[LayerName.Main].ColorData);

        //    imageFrame.Dispose();
        //}

        //public void UpdateMainLayerDepth(DepthImageFrame imageFrame)
        //{
        //    if (imageFrame == null)
        //    {
        //        return;
        //    }

        //    imageFrame.CopyPixelDataTo(Layers[LayerName.Main].DepthData);

        //    imageFrame.Dispose();
        //}

        //public void UpdateLayerDepth(short[] depthData, LayerName layer)
        //{
        //    Array.Copy(depthData, Layers[layer].DepthData, _PixelCount);
        //}

        byte[] _redPixel = new byte[] { 0, 0, 255, 0 };
        byte[] _bluePixel = new byte[] { 255, 0, 0, 0 };
        byte[] _clearPixel = new byte[] { 255, 255, 255, 255 };
        private int _framesRemaining;

        //public void MergeToOutput(KinectDepthTransform kinectTransform)
        //{
        //    foreach (LayerName layer in Layers.Keys)
        //    {
        //        if (LayerVisibility[layer])
        //        {
        //            Layers[layer].UpdateBitmaps();
        //        }
        //    }
        //}

        //public void UpdateOutputImage(Image imageSourceColor, Image imageSourceDepth)
        //{
        //    UpdateImage(imageSourceColor, imageSourceDepth, _Output);
        //}

        //public void UpdateImage(Image imageSourceColor, Image imageSourceDepth, LayerName layer)
        //{
        //    UpdateImage(imageSourceColor, imageSourceDepth, Layers[layer]);
        //}

        public void UpdateImage(Image imageSourceColor, Image imageSourceDepth, VideoMagicImage videoMagicImage)
        {
            if (imageSourceColor != null)
            {
                WriteableBitmap colorBitmap;

                if (imageSourceColor.Source == null)
                {
                    colorBitmap = new WriteableBitmap(
                        _Width,
                        _Height,
                        96,
                        96,
                        PixelFormats.Bgr32,
                        null
                        );

                    imageSourceColor.Source = colorBitmap;
                }
                else
                {
                    colorBitmap = (WriteableBitmap)imageSourceColor.Source;
                }

                colorBitmap.WritePixels(
                    _ViewPort,
                    videoMagicImage.ColorData,
                    videoMagicImage.ColorStride,
                    0);
            }


            if (imageSourceDepth != null)
            {
                WriteableBitmap depthBitmap;

                if (imageSourceDepth.Source == null)
                {
                    depthBitmap = new WriteableBitmap(
                        _Width,
                        _Height,
                        96,
                        96,
                        PixelFormats.Gray16,
                        null
                        );

                    imageSourceDepth.Source = depthBitmap;
                }
                else
                {
                    depthBitmap = (WriteableBitmap)imageSourceDepth.Source;
                }

                depthBitmap.WritePixels(
                    _ViewPort,
                    videoMagicImage.DepthData,
                    videoMagicImage.DepthStride,
                    0);
            }
        }

        public void UpdateMainLayerColor(VideoMagicImage currentFrame)
        {
            if (LayerVisibility[LayerName.Main])
            {
                Array.Copy(currentFrame.ColorData, Layers[LayerName.Main].ColorData, _PixelCount * _BytesPerColorPixel);
            }
        }

        //public DepthImagePixel[] MainLayerDepth
        //{
        //    get
        //    {
        //        //if (LayerVisibility[LayerName.Main])
        //        //{
        //        //return Layers[LayerName.Main].DepthData;
        //        //}
        //        //else
        //        //{
        //        return null;
        //        //}
        //    }
        //}

        public void CaptureBackground()
        {
            SetLayer(LayerName.Background, Layers[LayerName.Main]);
            _framesRemaining = 5;
        }

        public void SetForeground(VideoMagicImage foreground)
        {
            SetLayer(LayerName.Foreground, foreground);
        }

        public void SetLayer(LayerName layerName, VideoMagicImage imageSet)
        {
            Array.Copy(imageSet.ColorData, Layers[layerName].ColorData, _PixelCount * _BytesPerColorPixel);
            Array.Copy(imageSet.DepthData, Layers[layerName].DepthData, _PixelCount);
        }

        public void ShowHideMain()
        {
            LayerName layerName = LayerName.Main;
            VideoMagicImage layer = Layers[layerName];

            bool isVisible = !LayerVisibility[layerName];
            LayerVisibility[layerName] = isVisible;

            var maxDepth = new DepthImagePixel { };

            if (!isVisible)
            {
                Array.Copy(Layers[LayerName.Background].ColorData, 0, layer.ColorData, 0, 0);
                //layer.DepthData.Fill(maxDepth);
                layer.UpdateBitmaps();
            }
        }
    }
}
